#include <os/debug.h>
#include <os/spinlock.h>
#include <arch/config.h>
#include <arch/console.h>
#include <arch/debug.h>
#include <lib/stdarg.h>
#include <arch/cpu.h>
#include <lib/stdio.h>

char *msg[] =
    {
        "[SYSFAILD]",
        "[ERROR]",
        "[WARRNING]",
        "[NOTICE]",
        "[INFO]",
        "[DEBUG]",
        0};

DEFINE_SPIN_LOCK(kprint_lock);

void DebugPutStr(const char *str)
{
    while (*str != '\0')
        DebugPutC(*str++);
}

int KPrint(const char *fmt, ...)
{
    char buff[256];
    va_list arg = (char *)(&fmt) + 4;
    int i, count;
    char *p;
    int level = -1, show = 1;

    // format to buff
    i = vsprintf(buff, fmt, arg);
    count = i;
    p = buff;
    // check flags whether true
    if (*p == '<' && *(p + 1) >= '0' && *(p + 1) <= ('0' + DEBUG_FLAGS_MAX) && *(p + 2) == '>')
    {
        level = *(p + 1) - '0';
        // level too large
        if (level > DEBUG_FLAGS_MAX)
            show = 0;
        p += 3;
        count -= 3;
    }

    if (show)
    {
        if (level >= 0)
        {
            // put kernel msg
            DebugPutStr(msg[level]);
        }
        // put user msg
        DebugPutStr(p);
    }
}

void Spin(char *functionname)
{
    KPrint(PRINT_NOTICE "spinning is %s", functionname);
    DisInterrupt();
    while (1)
    {
        CpuIdle();
    }
}

void DumpVal(uint64_t val)
{
    KPrint(PRINT_DEBUG "debug:%d\n", val);
}

void Panic(const char *fmt, ...)
{
    char buff[256];
    va_list arg = (char *)(&fmt) + 4;
    int i, count;
    char *p;
    int level = -1, show = 1;

    // format to buff
    i = vsprintf(buff, fmt, arg);
    count = i;
    p = buff;
    // check flags whether true
    if (*p == '<' && *(p + 1) >= '0' && *(p + 1) <= ('0' + DEBUG_FLAGS_MAX) && *(p + 2) == '>')
    {
        level = *(p + 1) - '0';
        // level too large
        if (level > DEBUG_FLAGS_MAX)
            show = 0;
        p += 3;
        count -= 3;
    }

    if (show)
    {
        if (level >= 0)
        {
            // put kernel msg
            DebugPutStr(msg[level]);
        }
        // put user msg
        DebugPutStr(p);
    }

    while (1)
    {
        DisInterrupt();
        CPUhlt();
    }
}

void SysDebug(char *str)
{
    DebugPutStr(str);
}